<?php


namespace app\service\utils;


use app\common\exception\ApiException;
use EasyWeChat\Factory;

class WeiXinPayService
{
    protected $app;

    public function __construct($type = 0)
    {
        $config = [
            // 必要配置
            'app_id' => $type == 0 ? config('payment.miniprogram_app_id') : config('payment.official_app_id'),
            'mch_id' => config('payment.mch_id'),
            'key' => config('payment.mch_key'),   // API v2 密钥 (注意: 是v2密钥 是v2密钥 是v2密钥)

            // 如需使用敏感接口（如退款、发送红包等）需要配置 API 证书路径(登录商户平台下载 API 证书)
            'cert_path' => public_path() . config('payment.cert_pem_path'), // XXX: 绝对路径！！！！
            'key_path' => public_path() . config('payment.key_pem_path'),      // XXX: 绝对路径！！！！

            //'notify_url' => '默认的订单回调地址',     // 你也可以在下单时单独设置来想覆盖它
        ];
        $this->app = Factory::payment($config);
    }

    /**
     * @return \EasyWeChat\Payment\Application
     */
    public function getApp(): \EasyWeChat\Payment\Application
    {
        return $this->app;
    }

    /**
     * 下订单
     * @param $orderSn
     * @param $fee
     * @param $openId
     * @param $notifyUrl
     * @param $body
     * @param string $tradeType
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function pay($orderSn, $fee, $openId, $notifyUrl, $body, $tradeType = 'JSAPI')
    {
        $result = $this->app->order->unify([
            'body' => $body,
            'out_trade_no' => $orderSn,
            'total_fee' => intval($fee * 100),
            'notify_url' => $notifyUrl, // 支付结果通知网址，如果不设置则会使用配置里的默认地址
            'trade_type' => $tradeType, // 请对应换成你的支付方式对应的值类型
            'openid' => $openId,
        ]);
        if ($result['return_code'] != 'SUCCESS' || $result['result_code'] != 'SUCCESS') {
            throw new \Exception($result['err_code_des']);
        }
        $config = $this->app->jssdk->bridgeConfig($result['prepay_id'], false);
        return $config;
    }

    /**
     * 退款
     * @param $orderSn
     * @param $fee
     * @return bool
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     */
    public function refund($orderSn, $fee)
    {
        $result = $this->app->refund->byOutTradeNumber($orderSn, $orderSn, $fee, $fee);
        if ($result['return_code'] === 'FAIL') {
            throw new ApiException($result['return_msg']);
        }
        if ($result['result_code'] === 'FAIL') {
            throw new ApiException($result['err_code_des']);
        }
        return true;
    }

    /**
     * 企业付款到零钱
     * @param $orderSn
     * @param $openId
     * @param $name
     * @param $amount
     * @param $desc
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function toBalance($orderSn, $openId, $amount, $desc)
    {
        $result =  $this->app->transfer->toBalance([
            'partner_trade_no' => $orderSn, // 商户订单号，需保持唯一性(只能是字母或者数字，不能包含有符号)
            'openid' => $openId,
            'check_name' => 'NO_CHECK', // NO_CHECK：不校验真实姓名, FORCE_CHECK：强校验真实姓名
            // 're_user_name' => '王小帅', // 如果 check_name 设置为FORCE_CHECK，则必填用户真实姓名
            'amount' => $amount, // 企业付款金额，单位为分
            'desc' => $desc, // 企业付款操作说明信息。必填
        ]);
        if($result['result_code'] != 'SUCCESS'){
            throw new ApiException($result['err_code_des']);
        }
        return true;
    }
}